
const {
    wxpusher,
} = require('./ti_config');

const {
    logger,
    sleep,
    initPage,
    closeBrowser2,
    randBetween,
    httpPost,
    httpDelete,
    avoidNoticeFreq,
    waitOtherWorker,
    updateErrorTimes,
    closeRun,
    lpush,
} = require('./util');

const http = require('http');

const puppeteer = require('puppeteer-core');

const {
    readTask,
} = require('./ti_logic_read_task');

//全局捕获错误
process.on('unhandledRejection', error => {
    //...不处理处理...
});

let openSerials = [];//需要关注的规格

//每30秒重新拉取任务列表
(async () => {
    while (1) {
        const tasks = await readTask();
        if (!tasks) continue;
        const tmpSerials = [];
        for (const task of tasks) {
            if (task.status != 1) continue;
            tmpSerials.push(task.serial);
        }
        openSerials = tmpSerials;
        await sleep(30000);
    }
})();

//用随机数模拟页面滚动以及鼠标滑动
const randomScrollAndMouseMove = async page => {
    const x1 = randBetween(400, 1600);
    const y1 = randBetween(0, 300);
    const wait1 = randBetween(60, 120);
    const scrollY1 = randBetween(200, 500);
    logger('滚动页面到输入框处，并模拟鼠标滑动', x1, y1, wait1, scrollY1);
    await page.mouse.move(x1, y1, {steps:wait1});
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY1);
    const x2 = randBetween(200, 1500);
    const y2 = randBetween(300, 600);
    const wait2 = randBetween(60, 120);
    const scrollY2 = randBetween(500, 700);
    logger('模拟鼠标滑动', x2, y2, wait2, scrollY2);
    await page.mouse.move(x2, y2, {steps:wait2});
    await sleep(1000);
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY2);
}

const randomMoveAndClick = async page => {
    //鼠标随机移动4-6个地方
    const mouseMoveNum = randBetween(4, 6);
    logger('鼠标随机移动', mouseMoveNum, '次');
    for (let i=0; i<mouseMoveNum; i++) {
        const x = 10 + randBetween(100, 1700);
        const y = 110 + randBetween(200, 800);
        const steps = randBetween(30, 60);
        await page.mouse.move(x, y, {steps});
        await sleep(randBetween(200, 700));
    }

    logger('鼠标移动到输入框并点击');
    const targetInput = await page.$('ti-input');
    const box = await targetInput.boundingBox();
    const x1 = box.x + (box.width/2) - 3;
    const y1 = box.y + (box.height/2) - 2;
    const steps1 = randBetween(30, 60);
    await page.mouse.move(x1, y1, {steps:steps1});
    await page.mouse.click(x1, y1, {delay:200});
    await sleep(1000);
    logger('鼠标移出输入框并点击');
    const x2 = x1 - randBetween(100, 200);
    const y2 = y1 - randBetween(10, 200);
    const steps2 = randBetween(30, 60);
    await page.mouse.move(x2, y2, {steps:steps2});
    await page.mouse.click(x2, y2, {delay:100});
    await sleep(2000);
}
let profileId;
startProfile();
async function startProfile(){

  const ip_info = await getIp();

  logger('result=',ip_info);

  const ip_result = JSON.parse(ip_info);

  let mlaPort = 35000;

  //const result = await createProfile(ip_result['data'][0]);

  if(ip_result['data'].length<1){
    logger('打开快速下单页失败，将重启浏览器');
    await httpDelete('http://127.0.0.1:35000/api/v2/profile/'+profileId);
    await browser.close();
    return process.exit(1);
  }

  const result = await createProfile(ip_result['data']['proxy_list'][0]);

  logger('result=',result);

  const profileId_info = JSON.parse(result);

  profileId = profileId_info.uuid;

  logger('profileId=',profileId);

  /*Send GET request to start the browser profile by profileId.
  Returns web socket as response which should be passed to puppeteer.connect*/
 const ws = await http.get(`http://127.0.0.1:${mlaPort}/api/v1/profile/start?automation=true&puppeteer=true&profileId=${profileId}`, (resp) => {
  let data = '';
  let ws = '';

  

  //Receive response data by chunks
  resp.on('data', (chunk) => {
    data += chunk;
  });

  /*The whole response data has been received. Handling JSON Parse errors,
  verifying if ws is an object and contains the 'value' parameter.*/
  resp.on('end', () => {
    let ws;
    try {
      ws = JSON.parse(data);
    } catch(err) {
       // await closeBrowser(profileId, browser);
      console.log(err);
    }
    if (typeof ws === 'object' && ws.hasOwnProperty('value')) {
      console.log(`Browser websocket endpoint: ${ws.value}`);
      run(ws.value)
    }
  });

  }).on("error", (err) => {
    //await closeBrowser(profileId, browser);
    console.log(err.message);
  }).timeout(20000);

  // let page = await run(ws.value);
  // return page;
}

async function createProfile(ip){
    const tmp_ip = ip.split(':');
    const host = tmp_ip[0];
    const port = tmp_ip[1];
    // const host = ip['ip'];
    // const port = ip['port'];
    

    let os = 'mac';
    if (process.platform == 'win32') {
        logger(33);
        os = 'win';
    }

    logger('ip_info=',host+' '+port);

    const result = await httpPost('http://127.0.0.1:35000/api/v2/profile', JSON.stringify({
        name: new Date().getTime(),
        os: os,
        browser: "mimic",
        network:{
            proxy:{
                type:'SOCKS',
                host:host,
                port:port,
                username:'18767135671',
                password:'7kki4m5t'
            }
        }
    }), 'application/json');
    return result;
}

async function getIp(){    
    //const result = await httpPost('http://webapi.http.zhimacangku.com/getip?num=1&type=2&pro=&city=0&yys=0&port=2&pack=193720&ts=0&ys=0&cs=0&lb=1&sb=0&pb=4&mr=1&regions=');
    //const result = await httpPost('http://ecs.hailiangip.com:8422/api/getIp?type=2&num=1&pid=-1&unbindTime=600&cid=-1&orderId=O21111814053891278876&time=1637215756&sign=a0073f9d5076c00af21f8824e238ecdc&noDuplicate=0&dataType=0&lineSeparator=0&singleIp=');
    const result = await httpPost('https://v1.api.juliangip.com/dynamic/getips?num=1&pt=1&result_type=json&trade_no=1186437158587531&sign=2c3f319d69984ccceef15113d8562c56');
    return result;
}

const closeBrowser= async(profileId, browser) =>{  
    logger('打开快速下单页失败，将重启浏览器');
    await httpDelete('http://127.0.0.1:35000/api/v2/profile/'+profileId);
    await browser.close();
    return process.exit(1);
}


//程序主流程
async function run(ws){
    const browser = await puppeteer.connect({browserWSEndpoint: ws, defaultViewport:null});
    const page = await browser.newPage();
    logger('启动浏览器');
    try {
        await page.goto('https://www.ti.com.cn/zh-cn/ordering-resources/buying-tools/quick-add-to-cart.html');
        await page.waitForSelector('ti-input');
    } catch(e) {
        logger('打开快速下单页失败，将重启浏览器');
        await httpDelete('http://127.0.0.1:35000/api/v2/profile/'+profileId);
        await browser.close();
        return process.exit(1);
    }
    await randomScrollAndMouseMove(page);

    let timeoutCount = 0;
    let counter = 0;
    while (1) {
        logger('第', ++counter, '轮');

        //如果有其他进程在跑，等待
        //await waitOtherWorker();

        //鼠标随机移动和点击，有可能被卡住。如果超过n秒未完成，则强制跳过
        await Promise.race([
            randomMoveAndClick(page),
            sleep(20000),
        ]);

        logger('查询库存');
        try {
            const ret = await page.evaluate(async (serialStr) => {
                const ajax = () => {
                    return new Promise(resolve => {
                        const timer = setTimeout(() => {
                            resolve('timeout');
                        }, 20000);
                        const xhr = new XMLHttpRequest();
                        xhr.open('post', 'https://www.ti.com.cn/storeservices/cart/inventory', true);
                        xhr.setRequestHeader('Content-Type', 'application/json');
                        xhr.onreadystatechange = function(){
                            if (xhr.readyState == 4) {
                                if (xhr.status == 200) {
                                    resolve(xhr.responseText);
                                } else {
                                    resolve(xhr.statusText);
                                }
                                clearTimeout(timer);
                            }
                        };
                        xhr.send(serialStr);
                    });
                }
                const ret = await ajax();
                return ret;
            }, JSON.stringify(openSerials.sort(() => 0.5-Math.random())));

            logger('查询结果', ret);
            if (ret[0] == '{') {
                timeoutCount = 0;
                const retJson = JSON.parse(ret);
                let found = 0;
                for (const v of retJson.opn_list) {
                    if (v.purchase_flag == 'Y' && v.quantity > 0) {
                        found = 1;
                        const msg = `规格 ${v.orderable_number} 发现有 ${v.quantity} 库存可以下单`;
                        logger(msg);

                        //如果对应规格最近1小时内报告超过3次，则不再告警，避免信息轰炸
                        if (avoidNoticeFreq(v.orderable_number)) {
                            try {
                                //推送到队列，等待自动下单程序执行
                                await lpush('ti_worker_found', v.orderable_number);

                                //推送消息
                                await httpPost('http://wxpusher.zjiecode.com/api/send/message', JSON.stringify({
                                    appToken: wxpusher.appToken,
                                    content: msg,
                                    contentType: 1,
                                    uids: wxpusher.uids,
                                }), 'application/json');
                            } catch(e) {
                                logger(e);
                            }
                        }
                    }
                }
                if (!found) {
                    logger('本轮未检测到有库存');
                    await sleep(2000);
                }
            } else {
                //返回内容不是JSON，可能是被拦截了，等n秒后再重新请求
                await sleep(10000);
                timeoutCount++;
                await updateErrorTimes(timeoutCount);
                //连续n次timeout，退出重启浏览器
                if (timeoutCount >= 2) {
                    break;
                }
            }
        } catch(e) {
            logger('查询出错', e);
            await sleep(5000);
            continue;
        }
    }

    //await closeRun();
    logger('打开快速下单页失败，将重启浏览器');
    await httpDelete('http://127.0.0.1:35000/api/v2/profile/'+profileId);
    await browser.close();
    return process.exit(1);

};

